package com.tiancheng.trade.settlement.service.settlement.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.commom.core.utils.MD5Utils;
import com.tiancheng.trade.settlement.configuration.CmbConfiguration;
import com.tiancheng.trade.settlement.mapper.settlement.PaymentBankDataCmbBatch;
import com.tiancheng.trade.settlement.mapper.settlement.PaymentBankDataCmbMapper;
import com.tiancheng.trade.settlement.model.settlement.PaymentBankDataCmb;
import com.tiancheng.trade.settlement.service.settlement.ICmbSignService;
import com.tiancheng.trade.settlement.service.settlement.IPaymentBankDataCmbService;
import com.tiancheng.trade.settlement.service.settlement.IPaymentBankDataService;
import com.tiancheng.trade.settlement.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 支付明细对账
 */
@Service
@Slf4j
public class PaymentBankDataCmbService implements IPaymentBankDataCmbService {

    @Resource
    CmbConfiguration cmbConfiguration;

    @Resource
    ICmbSignService cmbSignService;

    @Resource
    JacksonJsonUtil jacksonJsonUtil;

    @Autowired
    PaymentBankDataCmbMapper paymentBankDataCmbMapper;

    @Autowired
    PaymentBankDataCmbBatch paymentBankDataCmbBatch;

    @Autowired
    IPaymentBankDataService paymentBankDataService;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 获取对账单下载地址
     *
     * @param billDate 下载对账单的日期
     * @return
     */
    private String getCmbMchordersStatementUrl(LocalDate billDate) {
        String requestUrl = String.format(cmbConfiguration.getMchordersStatementUrl(), cmbConfiguration.getDomain(), cmbConfiguration.getAppid());
        String requestMethod = "POST";
        String timestamp = CmbParaUtils.getTimeStr();
        String strBillDate = DateTimeUtil.format(billDate, "yyyyMMdd");
        Map<String, String> map = new HashMap<>();
        map.put("billDate", strBillDate);
        map.put("merId", cmbConfiguration.getTengyunMerchantCode());
        String bizContent = jacksonJsonUtil.toJson(map);
        SortedMap<String, Object> req = new TreeMap<String, Object>();
        req.put("biz_content", bizContent);
        req.put("version", "0.0.1");
        req.put("encoding", "UTF-8");
        req.put("signMethod", "01");
        String para = CmbParaUtils.getSignStr(req);
        String sign = cmbSignService.sign(para);
        req.put("sign", sign);
        SortedMap<String, Object> headerPara = new TreeMap<String, Object>();
        headerPara.put("appid", cmbConfiguration.getAppid());
        headerPara.put("secret", cmbConfiguration.getAppKey());
        headerPara.put("timestamp", timestamp);
        headerPara.put("sign", sign);
        String paraHeader = CmbParaUtils.getSignStr(headerPara);
        String apisign = MD5Utils.getMD5Content(paraHeader).toLowerCase();
        Map<String, Object> header = new HashMap<>();
        header.put("appid", cmbConfiguration.getAppid());
        header.put("timestamp", timestamp);
        header.put("apisign", apisign);
        header.put("Content-Type", "application/json");
        log.info("访问招商银行，获取对账单下载地址，请求的requestUrl:" + requestUrl + ",json:" + jacksonJsonUtil.toJson(req));
        String strResult = HttpUtil.httpsRequest(requestUrl, requestMethod, jacksonJsonUtil.toJson(req), header);
        log.info("访问招商银行，获取对账单下载地址，返回:" + strResult);
        return strResult;
    }

    /**
     * 获取对账单下载地址
     *
     * @param result 下载对账单的日期
     * @return
     */
    private String getFileDownloadUrl(String result) {
        String fileDownloadUrl = "";
        Map map = jacksonJsonUtil.fromJson(result, Map.class);
        if (map == null) {
            log.warn("招行返回数据转换map后为空!");
            return "";
        }
        String returnCode = map.get("returnCode").toString();
        if (!returnCode.equals("SUCCESS")) {
            log.warn("returnCode不正确，returnCode：" + returnCode);
            return "";
        }
        String bizContent = map.get("biz_content").toString();
        Map bizContentMap = jacksonJsonUtil.fromJson(bizContent, Map.class);
        String merId = bizContentMap.get("merId").toString();
        if (!merId.equals(cmbConfiguration.getTengyunMerchantCode())) {
            log.warn("merId不正确，merId：" + merId);
            return "";
        }
        if (bizContentMap.containsKey("fileDownloadUrl")) {
            fileDownloadUrl = bizContentMap.get("fileDownloadUrl").toString();
        }
        return fileDownloadUrl;
    }

    /**
     * 获取和保存招行支付对账文件
     *
     * @param billDate 对账单的日期
     * @return
     */
    @Override
    public String getAndSavePayCsv(LocalDate billDate) {
        String msg = "";
        String result = getCmbMchordersStatementUrl(billDate);
        String fileDownloadUrl = getFileDownloadUrl(result);
        log.info("fileDownloadUrl:" + fileDownloadUrl);
        if (StringUtils.isEmpty(fileDownloadUrl)) {
            msg = "fileDownloadUrl为空，result:" + result;
            log.warn(msg);
            return msg;
        }
        String strResult = HttpUtil.httpRequest(fileDownloadUrl, "GET", null, null);
        log.info("招行支付对账文件：" + strResult);
        String filePath = cmbConfiguration.getPaySavePath() + "CMB_" + DateTimeUtil.format(billDate, "yyyyMMdd") + ".csv";
        fileBack("CMB_", DateTimeUtil.format(billDate, "yyyyMMdd"));
        savePayCsv(filePath, strResult);
        List<PaymentBankDataCmb> listPaymentBankDataCmb = getPaymentBankDataCmb(filePath);
        savePaymentBankDataCmbBatch(listPaymentBankDataCmb);
        paymentBankDataService.savePaymentOrderBankBatch(listPaymentBankDataCmb);
        paymentBankDataService.savePaymentOrderBankDetailBatch(listPaymentBankDataCmb);
        return msg;
    }


    public List<PaymentBankDataCmb> getPayCsvDataList(LocalDate billDate) {
        String result = getCmbMchordersStatementUrl(billDate);
        String fileDownloadUrl = getFileDownloadUrl(result);
        log.info("fileDownloadUrl:" + fileDownloadUrl);
        if (StringUtils.isEmpty(fileDownloadUrl)) {
            log.warn("fileDownloadUrl为空，result:{}", result);
        }
        String strResult = HttpUtil.httpRequest(fileDownloadUrl, "GET", null, null);
        log.info("招行支付对账文件：" + strResult);
        String filePath = cmbConfiguration.getPaySavePath() + "CMB_" + DateTimeUtil.format(billDate, "yyyyMMdd") + ".csv";
        fileBack("CMB_", DateTimeUtil.format(billDate, "yyyyMMdd"));
        savePayCsv(filePath, strResult);
        List<PaymentBankDataCmb> listPaymentBankDataCmb = getPaymentBankDataCmb(filePath);
        return listPaymentBankDataCmb;
    }

    /**
     * 保存招行支付对账文件
     *
     * @param filePath 文件全路径
     * @param str      字符串
     */
    private void savePayCsv(String filePath, String str) {
        try {
            CsvUtils.writeFile(filePath, str);
        } catch (IOException e) {
            log.error("保存招行支付对账文件失败，异常信息：" + e.getMessage());
        }
    }

    /**
     * 从csv中获取支付对账数据
     *
     * @param filePath 文件全路径
     * @return
     */
    public List<PaymentBankDataCmb> getPaymentBankDataCmb(String filePath) {
        try {
            Object[][] arr = CsvUtils.getData(filePath, true, "UTF-8");
            List<PaymentBankDataCmb> list = new ArrayList<>();
            if (null != arr) {
                for (Object[] obj : arr) {
                    int i = 0;
                    PaymentBankDataCmb paymentBankDataCmb = new PaymentBankDataCmb();
                    paymentBankDataCmb.setMerOrderNo(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setBankSerialNumber(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setThirdOrderNo(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setPaymentWay(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setTransactionType(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setTradingCurrency(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setGoodsName(CsvUtils.GetString(obj[i++].toString()));
                    String strTransactionDatetime = CsvUtils.GetLocalDate(obj[i++].toString()) + " " + CsvUtils.GetString(obj[i++].toString());
                    LocalDateTime transactionDatetime = null;
                    //银行流水账单存在交易时间为空字符的情况
                    if (StringUtils.isNotEmpty(strTransactionDatetime) && !"null".equals(strTransactionDatetime.trim())) {
                        transactionDatetime = DateTimeUtil.format(strTransactionDatetime, "yyyy-MM-dd HH:mm:ss");
                    }
                    paymentBankDataCmb.setTransactionDatetime(transactionDatetime);
                    paymentBankDataCmb.setStoreName(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setStoreNo(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setCashier(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setPayerInformation(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setPayingBank(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setTransactionAmount(CsvUtils.GetAmount(obj[i++].toString()));
                    paymentBankDataCmb.setServiceCharge(CsvUtils.GetAmount(obj[i++].toString()));
                    paymentBankDataCmb.setSettlementAmount(CsvUtils.GetAmount(obj[i++].toString()));
                    paymentBankDataCmb.setRate(CsvUtils.getBigDecimal(obj[i++].toString()));
                    paymentBankDataCmb.setOriginalOrderAmount(CsvUtils.GetAmount(obj[i++].toString()));
                    paymentBankDataCmb.setFreeRechargeCouponAmount(CsvUtils.GetAmount(obj[i++].toString()));
                    paymentBankDataCmb.setEnterpriseRedPacketAmount(CsvUtils.GetAmount(obj[i++].toString()));
                    paymentBankDataCmb.setRefundAmountOfEnterpriseRedPacket(CsvUtils.GetAmount(obj[i++].toString()));
                    paymentBankDataCmb.setPlatformPreferentialAmount(CsvUtils.GetAmount(obj[i++].toString()));
                    paymentBankDataCmb.setStatementDate(CsvUtils.GetLocalDate(obj[i++].toString()));
                    paymentBankDataCmb.setCompletionDate(CsvUtils.GetLocalDate(obj[i++].toString()));
                    paymentBankDataCmb.setClearingDate(CsvUtils.GetLocalDate(obj[i++].toString()));
                    paymentBankDataCmb.setClearingAccount(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setClearingResult(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setOriginalMerchantOrderNo(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setOriginalBankSerialNumber(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setOriginalThirdOrderNo(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setBusinessType(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setMerchantReservationDomain(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setPayeeRemarks(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setPayerRemarks(CsvUtils.GetString(obj[i++].toString()));
                    paymentBankDataCmb.setRefundRemarks(CsvUtils.GetString(obj[i++].toString()));
                    list.add(paymentBankDataCmb);
                }
            }

            return list;
        } catch (Exception e) {
            log.error("获取招行支付对账数据失败，异常信息：" + e.getMessage());
            return null;
        }
    }


    /**
     * 获取需要保存的数据
     *
     * @param list 支付对账明细数据
     * @return
     */
    private List<PaymentBankDataCmb> getPaymentBankDataCmbForSave(List<PaymentBankDataCmb> list) {
        List<PaymentBankDataCmb> listSave = new ArrayList<>();
        for (PaymentBankDataCmb detailCmb : list) {
            PaymentBankDataCmb clearBankDetailCmb = getPaymentBankDataCmbMapper(detailCmb.getBankSerialNumber());
            if (clearBankDetailCmb == null) {
                listSave.add(detailCmb);
            }
        }
        return listSave;
    }

    /**
     * 保存支付对账明细数据
     *
     * @param list 支付对账明细数据
     */
    private void savePaymentBankDataCmbBatch(List<PaymentBankDataCmb> list) {
        try {
            List<PaymentBankDataCmb> listSaveBatch = getPaymentBankDataCmbForSave(list);
            if (listSaveBatch == null || listSaveBatch.size() == 0) {
                log.info("支付对账明细没有数据需要保存");
                return;
            }
            boolean bo = paymentBankDataCmbBatch.saveBatch(listSaveBatch);
            if (bo) {
                log.info("支付对账明细数据保存成功");
            } else {
                log.warn("支付对账明细数据保存失败");
            }
        } catch (Exception e) {
            log.error("保存支付对账明细数据,出现异常：{}", e.getMessage());
        }
    }

    /**
     * 查询支付对账明细数据
     *
     * @param bankSerialNumber 银行流水号
     * @return
     */
    private PaymentBankDataCmb getPaymentBankDataCmbMapper(String bankSerialNumber) {
        QueryWrapper<PaymentBankDataCmb> conditions = new QueryWrapper<>();
        conditions.eq("bank_serial_number", bankSerialNumber);
        return paymentBankDataCmbMapper.selectOne(conditions);
    }

    /**
     * 备份文件
     *
     * @param prefix 前缀
     * @param date   对账日期，格式为yyyyMMdd,如20240417
     */
    void fileBack(String prefix, String date) {
        try {
            String source = cmbConfiguration.getPaySavePath() + prefix + date + ".csv";
            String dest = cmbConfiguration.getPaySavePath() + prefix + date + "_" + System.currentTimeMillis() + ".csv";
            File sourceFile = new File(source);
            if (sourceFile.exists()) {
                Files.copy(sourceFile.toPath(), new File(dest).toPath());
            }
        } catch (IOException e) {
            log.error("备份文件出现异常：" + e.getMessage());
        }
    }

}
